package com.kancy.spring.boot.drools.config;

import com.kancy.spring.boot.drools.properties.DroolsProperties;
import com.kancy.spring.boot.drools.utils.KieUtils;
import org.drools.compiler.kie.builder.impl.ClasspathKieProject;
import org.drools.compiler.kie.builder.impl.KieContainerImpl;
import org.drools.compiler.kie.builder.impl.KieServicesImpl;
import org.kie.api.KieServices;
import org.kie.api.builder.KieModule;
import org.kie.api.builder.KieScanner;
import org.kie.api.builder.ReleaseId;
import org.kie.api.event.kiescanner.DefaultKieScannerEventListener;
import org.kie.api.event.kiescanner.KieScannerUpdateResultsEvent;
import org.kie.scanner.KieScannersRegistry;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Profile;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * RuleDynamicRefreshProcessor
 *
 * 动态刷新
 * 只有在开发和默认环境，才能使用
 * 使用前，必须加入依赖包：kie-ci
 * <p>
 *
 * @author: kancy
 * @date: 2020/4/3 18:38
 **/
@Profile({"dev","default"})
@ConditionalOnClass({KieScannersRegistry.class})
public class RuleDynamicRefreshProcessor implements InitializingBean, ApplicationListener<ApplicationStartedEvent> {

    @Autowired
    private DroolsProperties droolsProperties;

    /**
     * 启动标记
     */
    private volatile boolean started;

    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        started = true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setUp();
    }

    public void setUp() throws Exception {
        KieServicesImpl kieServices = (KieServicesImpl) KieServices.Factory.get();
        KieUtils.setKieClasspathContainer(kieServices.getKieClasspathContainer());

        Field kieModulesField = ReflectionUtils.findField(ClasspathKieProject.class, "kieModules");
        ReflectionUtils.makeAccessible(kieModulesField);
        Map<ReleaseId, KieModule> kieModules = (Map<ReleaseId, KieModule>) kieModulesField.get(((KieContainerImpl) KieUtils.getKieClasspathContainer()).getKieProject());

        Set<ReleaseId> releaseIds = kieModules.keySet();
        for (ReleaseId releaseId : releaseIds) {
            KieScanner kScanner = kieServices.newKieScanner(kieServices.newKieContainer(releaseId));
            kScanner.start(droolsProperties.getScanner().getInterval());
            kScanner.addListener(new DefaultKieScannerEventListener() {
                @Override
                public void onKieScannerUpdateResultsEvent(KieScannerUpdateResultsEvent kieScannerUpdateResultsEvent) {
                    if (started){
                        kieServices.nullKieClasspathContainer();
                        KieUtils.setKieClasspathContainer(kieServices.getKieClasspathContainer());
                    }
                }
            });
            kScanner.scanNow();
        }
    }

}
